<?php

namespace App\Kuafu\Mybank\Service;

use App\Exceptions\BaseException;
use App\Kuafu\Base\Service\BaseService;
use App\Kuafu\Mybank\Enum\MyBankWalletRecordEnum;
use App\Kuafu\Mybank\Model\MybankBalanceUnfreezeRecordModel;
use App\Kuafu\Mybank\Model\MybankBillRecordModel;
use App\Kuafu\Mybank\Model\MybankOrderRecordModel;
use App\Kuafu\Mybank\Model\MybankOrderWithholdRecordModel;
use App\Kuafu\Mybank\Model\MybankWalletRecordModel;
use App\Kuafu\Order\Service\OrderBrokerageService;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Model\WaiMaiOrderModel;
use App\Library\SnowFlake\SnowFlake;
use App\Remote\Mybank\MybankAccountRemote;
use App\Remote\Mybank\Remote;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Symfony\Component\HttpFoundation\Response as ResponseAlias;

/**
 * 协议代扣
 */
class MybankOrderWithholdService extends BaseService
{
    /**
     * 计算订单的账单日期
     *
     * @param int $shopId
     * @param int $id
     * @param int $source
     * @return array
     */
    public static function calcWaimaiDateTime(int $shopId, int $id, int $source): array
    {
        $list = MybankBillRecordModel::query()
                                     ->where('shopId', $shopId)
                                     ->where('transType', MybankBillRecordModel::INCOME_TRANS_TYPE)
                                     ->where('source', $source)
                                     ->where('id', '<', $id)
                                     ->where('billRecordBindId', 0)
                                     ->select(['id', 'shopId', 'transDate', 'billRecordBindId', 'billDate'])
                                     ->get();

        $timeList = $list->pluck('billDate');

        return $timeList->unique()->toArray() ?? [];

    }

    public static function calcWaimaiDateTimeInterval(int $shopId, int $id, int $source)
    {
        $timeList = self::calcWaimaiDateTime($shopId, $id, $source);
        sort($timeList);

        if (empty($timeList)) {
            return [];
        }

        $startAt = $timeList[0];
        $endAt   = $timeList[count($timeList) - 1];

        return [
            'startAt' => $startAt,
            'endAt'   => $endAt
        ];

    }

    /**
     * 更新关联的记录的billRecordBindId
     *
     * @param int $shopId
     * @param int $id
     * @param int $source
     * @return int
     */
    public static function updateBillRecordBillRecordBindId(int $shopId, int $id, int $source): int
    {
        return MybankBillRecordModel::query()
                                    ->where('shopId', $shopId)
                                    ->where('transType', MybankBillRecordModel::INCOME_TRANS_TYPE)
                                    ->where('source', $source)
                                    ->where('id', '<', $id)
                                    ->where('billRecordBindId', 0)
                                    ->update([
                                        'billRecordBindId' => $id
                                    ]);

    }

    /**
     * 计算连续的时间段
     *
     * @param array $timeList
     * @return array
     */
    public static function calcTimeList(array $timeList): array
    {
        $timeList = array_unique($timeList);
        asort($timeList);
        $timeList = array_values($timeList);

        $timeQuantum = [];

        $countTl = count($timeList);

        for ($i = 0; $i < $countTl; $i++) {
            $day     = 1;
            $startAt = $timeList[$i];
            for ($j = $i + 1; $j < $countTl; $j++) {
                // 是否连续
                if ($timeList[$j] - $timeList[$i] != $day * 86400) {
                    // 否
                    $timeQuantum[] = [
                        'startAt' => $startAt,
                        'endAt'   => $timeList[$j - 1] + 86399,
                    ];
                    $i             = $j - 1;
                    $j             = $countTl; // 终止后续的循环
                } else {
                    // 是
                    $day++;
                    if ($j + 1 >= $countTl) {
                        $timeQuantum[] = [
                            'startAt' => $timeList[$i],
                            'endAt'   => $timeList[$j] + 86399,
                        ];
                        $i             = $j - 1;
                    }
                }
            }
        }

        return $timeQuantum;
    }

    /**
     * 转换两者的 sourceType
     *
     * @param int $sourceType
     * @return int
     */
    public static function switchSourceTypeWaiMai(int $sourceType): int
    {
        switch ($sourceType) {
            case MybankBillRecordModel::SOURCE_ELE:
                return WaiMaiDBEnum::SOURCE_TYPE_ELM;
            case MybankBillRecordModel::SOURCE_MEITUAN:
                return WaiMaiDBEnum::SOURCE_TYPE_MT_WM;
            default:
                return 0;
        }
    }

    /**
     * 计算分佣总计
     *
     * @param int $shopId
     * @param array $timeList
     * @param int $billRecordSource
     * @return int|mixed
     */
    public static function calcBrokerSum(int $shopId, array $timeList, int $billRecordSource): int
    {
        if (empty($timeList)) {
            return 0;
        }

        $brokerSum = 0;

        switch ($billRecordSource) {
            case MybankBillRecordModel::SOURCE_MEITUAN:
            case MybankBillRecordModel::SOURCE_ELE:
                foreach ($timeList as $timeValue) {
                    $brokerSum = bcadd($brokerSum, (new WaiMaiOrderModel(['shopId' => $shopId]))
                        ->getBrokerageSum($timeValue['startAt'], $timeValue['endAt'] + 86399,
                            self::switchSourceTypeWaiMai($billRecordSource)));
                }
                break;
            case MybankBillRecordModel::SOURCE_CANTEEN:
                foreach ($timeList as $timeValue) {
                    $brokerSum = bcadd($brokerSum, (new OrderBrokerageService(0, $shopId))
                        ->getBrokerageSum($timeValue['startAt'],
                            $timeValue['endAt'] + 86399));
                }
                break;
        }


        return (int)$brokerSum;
    }

    /**
     * 更新外卖订单的分佣订单 ID
     *
     * @param int $shopId
     * @param array $timeList
     * @param int $billRecordSource
     * @param int $divisionBillId
     * @return bool
     */
    public static function updateOrderDivisionBillId(
        int $shopId,
        array $timeList,
        int $billRecordSource,
        int $divisionBillId
    ): bool {
        if (empty($timeList)) {
            return false;
        }

        switch ($billRecordSource) {
            case MybankBillRecordModel::SOURCE_MEITUAN:
            case MybankBillRecordModel::SOURCE_ELE:
                foreach ($timeList as $timeValue) {
                    (new WaiMaiOrderModel(['shopId' => $shopId]))
                        ->updateDivisionBillId($timeValue['startAt'], $timeValue['endAt'] + 86399,
                            self::switchSourceTypeWaiMai($billRecordSource), $divisionBillId);
                }
                break;
            case MybankBillRecordModel::SOURCE_CANTEEN:
                foreach ($timeList as $timeValue) {
                    (new OrderBrokerageService(0, $shopId))
                        ->updateDivisionBillId($timeValue['startAt'], $timeValue['endAt'] + 86399, $divisionBillId);
                }
                break;
        }

        return true;
    }


    /**
     * 余额解冻
     *
     * @param int $balanceFreeze
     * @param MybankOrderWithholdRecordModel $withholdModel
     * @return void
     * @throws BaseException
     * @throws GuzzleException
     */
    public static function unfreezeBalance(int $balanceFreeze, MybankOrderWithholdRecordModel $withholdModel)
    {

        if ($balanceFreeze <= 0) {
            return;
        }

        /*** 余额解冻记录 ***/
        $outTradeNo                = SnowFlake::nextIdCache();
        $balanceModel              = new MybankBalanceUnfreezeRecordModel();
        $balanceModel->merchantId  = $withholdModel->payerId;
        $balanceModel->withholdId  = $withholdModel->id;
        $balanceModel->outTradeNo  = $outTradeNo;
        $balanceModel->accountType = 'BALANCE';
        $balanceModel->amount      = $balanceFreeze;
        $balanceModel->currency    = 'CNY';
        $balanceModel->save();


        // 余额解冻
        $unfreezeApplyResult = MybankAccountRemote::unfreezeApply($withholdModel->payerId, $balanceFreeze,
            $outTradeNo);

        if (Remote::checkBodySuccess($unfreezeApplyResult)) {
            $balanceModel->status         = MybankOrderWithholdRecordModel::WITHHOLD_STATUS_SUBMIT;
            $balanceModel->operateNo      = $unfreezeApplyResult['OperateNo'];
            $balanceModel->submitDateTime = time();
            $balanceModel->save();
        } else {
            // 异常报错
            throw new \Exception(0, '解冻余额异常');
        }
    }

    /**
     * 解冻通知
     *
     * @param array $requestBody
     * @return array
     */
    public static function unfreezeNotify(array $requestBody)
    {
        $unfreezeModel = MybankBalanceUnfreezeRecordModel::query()
                                                         ->where('outTradeNo', $requestBody['OutTradeNo'])
                                                         ->first();

        if (empty($unfreezeModel)) {
            // TODO 记录异常
            return [ResponseAlias::HTTP_OK, []];
        }


        if ($requestBody['Status'] == 'SUCCESS' && !empty($requestBody['FinishTime'])) {
            $unfreezeModel->finishDateTime = strtotime($requestBody['FinishTime']);
            $unfreezeModel->status         = MybankOrderWithholdRecordModel::WITHHOLD_STATUS_SUCCESS;


        } else {
            $unfreezeModel->status    = MybankOrderWithholdRecordModel::WITHHOLD_STATUS_FAIL;
            $unfreezeModel->errorCode = $requestBody['ErrorCode'];
            $unfreezeModel->errorDesc = $requestBody['ErrorDesc'];
        }

        $unfreezeModel->save();

        return [ResponseAlias::HTTP_OK, []];
    }

    /**
     * 添加钱包记录
     *
     * @param string $merchantId
     * @param int $transType
     * @param int $transAmount
     * @param int $afterRemainingAmount
     * @param int $shopId
     * @param int $recordId
     * @param int $recordIdType
     * @param int $platformType
     * @param string $transDesc
     * @param string $transId
     * @param string $remark
     * @param int $transDate
     * @param int $status
     * @param int $isShow
     * @return MybankWalletRecordModel|Builder|Model|object
     */
    public static function walletRecordAdd(
        string $merchantId,
        int $transType,
        int $transAmount,
        int $afterRemainingAmount,
        int $shopId = 0,
        int $recordId = 0,
        int $recordIdType = 0,
        int $platformType = 0,
        string $transDesc = '',
        string $transId = '',
        string $remark = '',
        int $transDate = 0,
        int $status = 0,
        int $isShow = 0
    ) {
        $record = MybankWalletRecordModel::query()->where('transId', $transId)->first();

        if ($record && config('app.env') != 'pre') {// pre环境受正式环境影响
            return $record;
        }
        $supplyChainBalance = 0;
        // 如果是订货支付去查供应链账户金额
        if ($transDesc == MybankOrderRecordModel::WALLET_TYPE_SHOW_TYPE_TEXT[MybankOrderRecordModel::TYPE_KFOS_ORDER]) {
            $result             = MybankService::getMerchantBalance(Remote::getKfosBankMerchantId());
            $supplyChainBalance = $result['PAY'] ?? 0;
        }

        // 判断写入数据的类型
        $balanceModel                       = new MybankWalletRecordModel();
        $balanceModel->shopId               = $shopId;
        $balanceModel->merchantId           = $merchantId;
        $balanceModel->recordId             = $recordId;
        $balanceModel->recordIdType         = $recordIdType;
        $balanceModel->platformType         = $platformType;
        $balanceModel->transDate            = $transDate ?: time();
        $balanceModel->transType            = $transType;
        $balanceModel->displayTransType     = MybankWalletRecordModel::MAPPING_TRANS_TYPE[$transType];
        $balanceModel->transDesc            = $transDesc;
        $balanceModel->transId              = $transId;
        $balanceModel->transAmount          = $transAmount;
        $balanceModel->afterRemainingAmount = $afterRemainingAmount;
        $balanceModel->supplyChainBalance   = $supplyChainBalance;
        $balanceModel->remark               = $remark;
        $balanceModel->status               = $status;
        $balanceModel->isShow               = $isShow;
        $balanceModel->walletRecordType     = MybankOrderWithholdService::getWalletRecordTypeByModel($transType,
            $transDesc);

        $balanceModel->save();

        return $balanceModel;
    }


    /**
     * 根据 Model 返回 walletRecordType
     *
     * @param int $transType
     * @param string $transDesc
     * @return int
     */
    public static function getWalletRecordTypeByModel(int $transType, string $transDesc = ''): int
    {
        $walletRecordType = 0;
        switch ($transType) {
            case MybankWalletRecordModel::INCOME_TRANS_TYPE:
                // 提现支出
                $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_OUT_WITHDRAWAL;
                break;
            case MybankWalletRecordModel::PAY_TRANS_TYPE:
                switch ($transDesc) {
                    // 服务费 支出
                    case MybankOrderRecordModel::WALLET_TYPE_SHOW_TYPE_TEXT[MybankOrderRecordModel::TYPE_BROKERAGE]:
                        $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_OUT_SERVER;
                        break;
                    // 订货支出
                    case MybankOrderRecordModel::WALLET_TYPE_SHOW_TYPE_TEXT[MybankOrderRecordModel::TYPE_KFOS_ORDER]:
                        $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_OUT_GOODS;
                        break;
                }
                break;
            case MybankWalletRecordModel::RECHARGE_TRANS_TYPE:
                // 网商充值
                $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_INCOME_PAY;
                break;
            case MybankWalletRecordModel::EARNING_TRANS_TYPE:
                switch ($transDesc) {
                    // 美团收入
                    case MybankBillRecordModel::MAPPING_SOURCE[MybankBillRecordModel::SOURCE_MEITUAN]:
                        $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_INCOME_MT;
                        break;
                    // 饿了么收入
                    case MybankBillRecordModel::MAPPING_SOURCE[MybankBillRecordModel::SOURCE_ELE]:
                        $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_INCOME_ELM;
                        break;
                    // 堂食收入
                    case MybankBillRecordModel::MAPPING_SOURCE[MybankBillRecordModel::SOURCE_CANTEEN]:
                        $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_INCOME_CASH;
                        break;
                    // 服务费退款
                    case MybankOrderRecordModel::WALLET_TYPE_SHOW_TYPE_TEXT[MybankOrderRecordModel::TYPE_BROKERAGE]:
                        $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_REFUND_SERVER;
                        break;
                    // 订货退款
                    case MybankOrderRecordModel::WALLET_TYPE_SHOW_TYPE_TEXT[MybankOrderRecordModel::TYPE_KFOS_ORDER]:
                        $walletRecordType = MyBankWalletRecordEnum::WALLET_RECORD_TYPE_REFUND_GOODS;
                        break;
                }
                break;
        }


        return $walletRecordType;
    }

}
